home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / mmu / MuManual / Autodocs / exceptions.doc < prev    next >
Text File  |  2002-03-12  |  37KB  |  818 lines

  1.         E X C E P T I O N - H A N D L E R   D E T A I L S
  2. ------------------------------------------------------------------------------
  3. Abstract:
  4.     This document defines the exception handler mechanism of the mmu.library
  5.     and how to make use of it.
  6.     Please study it carefully before you try to implement an mmu.lib
  7.     exception handler. 
  8.  
  9.     For details about the concepts of a "context", read the mmu.doc.
  10. ------------------------------------------------------------------------------
  11. What is a bus error exception:
  12.  
  13.     A bus error can be understood as a sort-of "interrupt" which is triggered
  14. by either a software fault or a hardware signal related to acessing memory
  15. or external devices in an unsupported fashion, like accessing a non-available
  16. memory location or writing to a write-protected memory region.
  17.  
  18. All bus errors are re-directed to the MMU.library, but some of them remain
  19. unhandled and are passed over to the exec.library. Some of the remaining
  20. errors are handled automatically by the library, and those that remain
  21. will cause your "context hooks" to be called, as installed by the
  22. "AddContextHook" and "AddMessageHook" vectors of the mmu.library.
  23.  
  24.  
  25. The members of the MC680x0 family generate so called "bus error" for the
  26. following situations:
  27.  
  28. - True physical bus errors: 
  29.  
  30.     The CPU tried to access an external device, but this request was aborted
  31.     by pulling the "bus error input" control line (TEA) of the CPU low. 
  32.     These bus errors are generated by an external bus control logic, avail-
  33.     able for some Amiga models, on access of non-available memory.
  34.  
  35. - Access errors:
  36.  
  37.     These errors are generated by the MMU for a non-valid access of
  38.     a memory "page". As far as the MMU is concerned, complete memory is
  39.     split into adjacent pages of a fixed size, usually of size 1K or 4K,
  40.     and the MMU holds access rules, the so called "properties" for each
  41.     of these pages. If these rules are violated, an access error is
  42.     generated. The following violations may arise:
  43.  
  44.     The CPU tried to access a page of memory marked by the MMU as 
  45.     "non-resident", or tried to write to a memory block which is write-
  46.     protected, or tried to access a memory block in user mode which is
  47.     marked as "supervisor only" access.
  48.  
  49. Of all of these bus errors, the mmu.library handles only the part which it
  50. is "interested in". True physical bus errors are not handled by the 
  51. MMU.library and passed thru to the exec exception handler - which again, calls
  52. the exception handler of the task that caused the exception. Additionally,
  53. the MMU.library does not try to fix bus errors caused by so called "locked
  54. transfers", i.e. the instructions "TAS","CAS" and "CAS2". These instructions
  55. are only useful for multi-processor machines and not supported by the Amiga
  56. hardware architecture anyways. A legal Amiga program *must not* use them.
  57.  
  58. Furthermore, the "MOVE16" instruction accesses of the 040 and 060 processors
  59. should not be expected to handled fully correctly, too, for the same reason. 
  60. The exception handler cannot guarantee that no "double read" situation can
  61. occur; i.e. the handler might then read one location more than once, which
  62. might be undesirable if someone is insane enough to use MOVE16 for a hardware
  63. access.
  64.  
  65. An additional special case - which might be interesting for the experts -
  66. is writing to memory by "instruction function code". This is only possibly
  67. by loading this function code to the "dfc" register and then using the
  68. privileged "moves" instruction to write instruction data. This is unsupported,
  69. too. Just write instructions with "move", then flush the cache. This is, too,
  70. what the dos.library does when loading code; alternatively, make sure
  71. that this write operation cannot fail. Note that you have to push the
  72. corresponding cache entry anyhow.
  73.  
  74.  
  75. All remaining accesses are handled by the MMU library, and are first filtered
  76. again. The MMU library distinguishes:
  77.  
  78. -    User mode and supervisor mode accesses.
  79.  
  80. All exec tasks MUST run in user mode, and this is the "default" situation.
  81. The user mode exceptions are handled according to the "MMU context" they
  82. are generated by, or, equivalently, the context the current task is attached
  83. to. All supervisor mode accesses are managed by the supervisor context of
  84. the currently active context. Usually, there is only one supervisor context
  85. which is shared amongst all user contexts.
  86.  
  87. -    Data vs. instruction accesses.
  88.  
  89. Whether the bus error happened due to faulted access of data, or whether 
  90. the CPU tried to fetch instructions, and this instruction fetch faulted.
  91. Instruction write accesses, as they might have been generated by a "moves",
  92. might or might not be handled, this is implementation specific. The CPU
  93. itself never generates these accesses when fetching code, the only 
  94. possibility is a "moves" instruction.
  95.  
  96. -    Read vs. write accesses.
  97.  
  98. Whether data was about to be read by the CPU, or the CPU tried to write
  99. out data. Instruction accesses by the CPU are always reads.
  100. Accesses to the stack, as for subroutine calls or "link" instructions
  101. are regarded as data accesses, too. (Read about special caveats about
  102. the stack, below!)
  103. If the CPU fetches an auto vector for an interrupt or any other exception
  104. management, then this access is a "supervisor data space access", and
  105. goes thru the cache. It might not allocate a cache line, though. 
  106.  
  107. Amongst all these types, the MMU library handles certain special cases
  108. automatically. You never see these faults from your context hooks, they
  109. are completely transparent and handled by the library as a special service.
  110.  
  111. -     AbsExecBase reads.
  112.  
  113. To be able to mark the first memory page as "invalid", the MMU library
  114. filters out accesses to AbsExecBase itself in the first stage of the exception
  115. handler, to emulate them as fast as possible. The library will try to emulate
  116. the most popular instructions in software, for optimal performance. However,
  117. still try to avoid reading AbsExecBase in your code. Make a copy to a static
  118. library base on startup, and then use this backup copy whenever possible.
  119. Most modern C compilers do that automatically anyways, but assembly language
  120. authors should keep this in mind.
  121.  
  122.     DON'T (slow!)                    DO (fast)
  123.  
  124.     move.l AbsExecBase,a6            move.l mn_SysBase(a4),a6
  125.  
  126.  
  127. In case the special threatment of AbsExecBase is not desired, set the 
  128. MCXTAG_EXECBASE tag value of the CreateMMUContext() call to FALSE. This might
  129. be interesting for emulators, for example.
  130.  
  131. Remember that interrupt code is handled by a supervisor context, AND NOT
  132. BY YOUR USER CONTEXT. Hence, accessing AbsExecBase from within interrupts is
  133. always valid, simply because the supervisor context is always build by the
  134. library itself, and this flag is always set on creation of this context. 
  135. DO NOT touch the default supervisor context unless you know precisely what 
  136. you're doing. Note that all exec interrupt handlers run thru an AbsExecBase
  137. access!
  138.  
  139.  
  140. -    Legal accesses in the first memory page.
  141.  
  142. The mmu.library emulates accesses into valid "chip memory" addresses in the
  143. first page in memory. This is again to allow configuring the first page as 
  144. "invalid" for tracing access errors in the autovector region. Accesses to 
  145. addresses above and including the chip memory start in the first page are 
  146. therefore always legal, but slow. These accesses should not happen for 
  147. Os 3.0 or better since chip memory starts for newer Os releases always 
  148. in the second page. This feature can be disabled again with the 
  149. MCXTAG_EXECBASE flag, and can be configured by the MCXTAG_LOWMEMORYLIMIT
  150. tag item.
  151.  
  152. AVOID THESE ACCESSES, THEY ARE EMULATED IN SOFTWARE AND VERY SLOW.
  153.  
  154. Starting with Os 3.0, exec tries to help these MMU programs by starting 
  155. chip memory at 0x1000, not at 0x0400 as usual, if a 040 or 060 CPU is
  156. available. This means that for page sizes of 4K for the 040 and 060, and
  157. for page sizes of 1K for the 030 and 68851/020 MMU, no accesses need to
  158. be emulated. Please keep this in mind when using the MMU because THE 
  159. EMULATION CODE IS SLOW. Try to use these "natural" page sizes whenever 
  160. possible.
  161.  
  162. If not possible, try to relolate the libraries and buffers in this memory
  163. region, usually some graphics.library buffers, the expansion library base,
  164. and - possibly - the exec library. MuMove4K will do this for you.
  165.  
  166.  
  167. - Writes to MAPP_ROM pages.
  168.  
  169. The mmu.library tries to cancel writes to pages marked as "ROM". Writes
  170. to these pages will generate an access error, which is "ignored" by
  171. the mmu.library. Hence, memory regions marked as "ROM" will get an
  172. effective "silent" write protection. However, keep in mind that a write
  173. to "ROM" area is still slow because it includes running the exception handler.
  174. This goes even more for the 060 CPU because it includes copying the "ROM"
  175. to a dummy writable backup page into which the write is then redirected.
  176. A 060 cannot be stopped once it intends to write to memory.
  177.  
  178. Special care must be taken for "misaligned" writes, i.e. writes that hit
  179. the "border" of a ROM region and go partially into valid RAM, and partially
  180. into "ROM" regions. The MMU.library DOES NOT guarantee that the valid part
  181. of the access is performed! It might abort the complete write!
  182.  
  183. This shouldn't be much of a problem because writes to ROM should only happen
  184. due to faulty software, and it should only do good to abort these writes
  185. completely.
  186.  
  187.  
  188. To say that again: All the cases above are handled by the library trans-
  189. parently, you don't see them from your context hook. However, the following
  190. cases ARE seen from your hook function:
  191.  
  192.  
  193. - Access to MAPP_SWAPPED pages.
  194.  
  195. If a read or write hits a page marked as swapped, the library calls all
  196. hooks in its "swapped" hook list. For details what happens then, see below.
  197.  
  198. Again, special care must be taken if the access is "misaligned", i.e. hits
  199. more than one page at once. In this case, the library checks if both accesses
  200. are allowed, i.e. go either to valid pages, or to swapped pages. In case
  201. any of the accesses is invalid, the "segmentation fault" hook list, see 
  202. below, is called.
  203.  
  204.  
  205. - Any other access,
  206.  
  207. as there are accesses to "MAPP_INVALID" pages or to supervisor only pages
  208. in user mode, or write accesses to write protected pages are passed over
  209. to the "segmentation fault" hook list.
  210.  
  211.  
  212. How your hook function is called:
  213. ---------------------------------
  214.  
  215. The mmu.library keeps two priority sorted lists for each MMU context, one
  216. for the "swapped" hook list for pages currently "swapped out", and another
  217. for the "segmentation fault" hook lists. The mmu library first determinates
  218. which list has to be used to handle the access, and then tries to find the
  219. right handler. The following algorithm is used:
  220.  
  221.     - Try the handler of higher priorities first;
  222.     - Check whether this hook is activated or not, skip it if it is
  223.       deactivated;
  224.     - Check whether the hook is "task specific", i.e. whether the
  225.       MADTAG_TASK tag was given at the time the hook was added with
  226.       AddContextHook().
  227.       If the hook is task specific, check whether the faulty task
  228.       is identical to the task handled by the hook and skip the
  229.       handler if this is not the case.
  230.     - As soon as a match has been found, call the routine at the
  231.       address provided by the MADTAG_CODE tag. This should be an
  232.       assembly routine, mainly for speed reasons. Furthermore,
  233.       parameters are passed in registers, similar to the exec.library
  234.       interrupts, and return values have to be provided in the d0
  235.       register and in the "Z" bit of the processor.
  236.  
  237. You're called like this:
  238.     
  239.     Register a0 contains a pointer the exception data structure,
  240.     discussed below.
  241.  
  242.     Registers a1 and a4 contain the data provided by the MADTAG_DATA
  243.     tag on creation.
  244.  
  245.     Register a6 contains the pointer to the mmu.library base.
  246.  
  247.     Register a5 contains the pointer to your code.
  248.  
  249. You may alter registers d0-d1, a0-a1 and a4-a5. They will be restored by the 
  250. library automatically. All other registers MUST BE preserved.
  251.  
  252. In case you want make use of the exception data structure, please keep in 
  253. mind that it is only valid as long as your exception hook executes. That 
  254. means that you possibly have to make a copy of it for later use.
  255.     
  256. Remember, too, that you're called in supervisor mode, with all interrupts
  257. disabled. DO NOT ACCESS ABSEXECBASE IN YOUR CODE, use either a private
  258. copy, or the copy in the ExceptionData structure below. Accessing
  259. AbsExecBase MIGHT BE FATAL!
  260. Additionally, THERE IS NO DIRECT ACCESS to the CPU specific exception
  261. stack frame. Exception hooks are - and that's the great point about the
  262. mmu library - CPU indepentent. All data you need is provided in the
  263. exception data structure, DO NOT MAKE ANY ASSUMPTIONS which CPU you're 
  264. running at, or how the stack frame looks like. This is the matter of the
  265. library.
  266.  
  267.  
  268. On return, you should set d0 to 0 and set the zero flag to indicate that
  269. your exception handler was able to handle the fault and return to the
  270. library with a plain "RTS". In that case, the library will no longer look 
  271. for more handlers.
  272. If you haven't been able to handle the fault, return 1 in d0 and clear
  273. the zero flag (i.e. return a "ne" condition in the CCR register). 
  274.  
  275. In case the library did not find any hook that claimed to be able to 
  276. repair the fault, it will redirect control back to the exec exception
  277. handler (which will, by default, run the GURU).
  278.  
  279. BE WARNED! Another bus error within the bus error handler IS FATAL AND WILL
  280. CAUSE A GURU! Within the exception handler, YOU MUST ENSURE that all memory
  281. accesses are valid or you're lost. The library function GetPagePropertiesA() 
  282. is ideal for this purpose: First, it is safe to get called within interrupts
  283. and bus errors, it is rather optimized and you find all information required
  284. to call it in the ExceptionData structure.
  285.  
  286. The ExceptionData structure
  287. ---------------------------
  288.  
  289. This structure is the key to the powers of the MMU. Your handler is called
  290. with a pointer in *a0 to this structure:
  291.  
  292. struct ExceptionData {
  293.     struct Task                *exd_Task;
  294.     struct MMUContext            *exd_Context;
  295.     ULONG                    *exd_Descriptor;
  296.     ULONG                    *exd_NextDescriptor;
  297.     APTR                     exd_FaultAddress;
  298.     APTR                     exd_NextFaultAddress;
  299.     ULONG                     exd_UserData;
  300.     ULONG                     exd_NextUserData;
  301.     ULONG                     exd_Data;
  302.     APTR                     exd_ReturnPC;
  303.     ULONG                     exd_Flags;
  304.     ULONG                     exd_Properties;
  305.     ULONG                     exd_NextProperties;
  306.     UBYTE                     exd_internal;
  307.     UBYTE                     exd_FunctionCode;
  308.     UBYTE                     exd_Level;
  309.     UBYTE                     exd_NextLevel;
  310.     ULONG                     exd_DataRegs[8];
  311.     ULONG                     exd_AddrRegs[7];
  312.     UWORD                    *exd_SSP;
  313.     UWORD                    *exd_USP;            
  314.     struct ExecBase                *exd_SysBase;
  315.     struct MMUBase                *exd_MMUBase;
  316. };
  317.  
  318. Let's discuss the fields in this structure:
  319.  
  320. exd_Task        contains the pointer to the task structure of the task 
  321.             that caused the exception.
  322.             If this hook was added to a supervisor context, this
  323.             field is meaningless and must be left alone.
  324.  
  325. exd_Context        contains the ID of the MMU context responsible for the
  326.             fault. This is always the context the hook was added to.
  327.  
  328. exd_Descriptor        contains a pointer to the true hardware MMU descriptor which
  329.             handles the fault. This is usually of less interest except
  330.             for special purposes.
  331.             In case of an indirect descriptor, this points NOT to the
  332.             final page descriptor, but to the indirect descriptor.
  333.  
  334.             WARNING! In case you read this descriptor or write a new
  335.             one, you *MUST* call CacheClearE() to make sure that the
  336.             descriptor is really written out. The library will always
  337.             flush descriptors correctly. Do *NOT* expect descriptors in
  338.             non-cacheable memory.
  339.  
  340. exd_NextDescriptor    In case of a misaligned access, i.e. an access that
  341.             spawns two pages because it hit a page boundary, this is the 
  342.             descriptor for the end address of the access, and 
  343.             exd_Descriptor is the descriptor for the first address
  344.             of the access. If the access is aligned, both pointers are
  345.             identically.
  346.             NOTE THAT THIS DESCRIPTOR NEED NOT TO POINT TO A HIGHER
  347.             ADDRESS. An example for a "backwards" misaligned access is
  348.                 the "movem.l regs,-(ax)" instruction.
  349.  
  350.             WARNING! In case you read this descriptor or write a new
  351.             one, you *MUST* call CacheClearE() to make sure that the
  352.             descriptor is really written out. The library will always
  353.             flush descriptors correctly.
  354.             
  355. exd_FaultAddress    The address that faulted, the start address of the access.
  356.  
  357. exd_NextFaultAddress    The end address of the access that faulted, inclusive.
  358.             For a long word access, this would be exd_FaultAdress + 3,
  359.             for a byte access, this would be identically to 
  360.             exd_FaultAdress.
  361.             Note that it may well be that exd_NextFaultAddress is a
  362.             SMALLER address than exd_FaultAdress. This might, for example,
  363.             happen for a movem with pre-decrement addressing mode, i.e.
  364.             a "movem.l d0-d7/a0-a6,-(a7)". Exception handlers must be
  365.             aware of this special situation.
  366.             Especially, it *might* happen that the library is not
  367.             able to report the full range of the access violation, but
  368.             only a part of the violation. However, it will always
  369.             report enough to ensure that all memory pages that
  370.             participate in this fault can get corrected. In the
  371.             above situation, the library *might* only report the long
  372.             word access hitting the page boundary such that you
  373.             get notice that two pages are involved in the operation,
  374.             not one.
  375.  
  376. exd_UserData        The user data provided for invalid and swapped pages, as
  377.             defined by SetPropertiesA() and SetPagePropertiesA().
  378.             This will be NULL in case no user data is available.
  379.  
  380. exd_NextUserData    In case of a misalgined access, the user data of the
  381.             second page that was involved in the exception. If the
  382.             access was aligned, this is identical to exd_UserData.
  383.  
  384. exd_Data        If the access was a write access and the 
  385.             EXDF_WRITEDATAUNKNOWN flag (see below) is cleared, then
  386.             this long word will contain the data the CPU tried to
  387.             write out. The data is right-justified in this field, i.e.
  388.             bytes will use bits 7..0, words will use bits 15..0 and
  389.             long word accesses will use the complete field.
  390.             The size is available by subtracting the exd_FaultAddress and
  391.             exd_NextFaultAddress fields.
  392.             On movem faults, the complete write data is unfortunately
  393.             not available. You may see movem faults as a series of
  394.             long word writes on some CPUs, while this instruction is
  395.             atomic on other CPUs. There's nothing the MMU library can
  396.             do for you here.
  397.             This data should be used only for debugging purposes and
  398.             "Enforcer like" applications, and for applications where you
  399.             can guarantee that movems do not occur, i.e. emulators that
  400.             threat "computer hardware" by the MMU and might read the
  401.             data written to the emulated hardware right here.
  402.  
  403.             To allow the MMU library to fetch write data, you *MUST*
  404.             set the "MAPP_REPAIRABLE" bit of pages you want write data
  405.             for. In all other cases, you *might* get write data, but
  406.             this is a matter of "good luck". (Or, in other words, I don't
  407.             want to document the messy details.)
  408.             Please do only set this bit in case you really need the
  409.             write data because it means much more work for the library
  410.             and much "higher magic" to get it, especially for the 060
  411.             CPU.
  412.  
  413.             In case you want to allow the CPU to continue execution and
  414.             you somehow managed to write out the data itself (or you
  415.             want to ignore the faulty access), set the 
  416.             EXDF_WRITECOMPLETE bit of the flags field below.
  417.  
  418.             In case you do not set this bit, the CPU will attempt to
  419.             re-run the faulty instruction. In case you haven't been able
  420.             to repair the fault using some other technique (as for
  421.             example by swapping in the faulty page), your exception
  422.             handler will be called again.
  423.  
  424.             In case of a read fault, you may place the data to be 
  425.             read back in this field and set the EXDF_READBACK flag
  426.             in the flags value below. The MMU library will then
  427.             attempt to place this value in the input pipe of the CPU
  428.             and to repair the faulty access by providing this dummy
  429.             data. The data has to be placed right-justified in this
  430.             field again.
  431.  
  432.             Certain restrictions arise, again:
  433.  
  434.             First, a movem might show up as several exceptions, hence
  435.             you might be able to provide data for each register loaded,
  436.             or it might show up as one single exception. In this case,
  437.             all registers will be loaded with the same value. (It was
  438.             hard enough to emulate this, so please don't complain...)
  439.                 
  440.             Instruction faults can't be repaired like this. (I would
  441.             have been able to provide this exclusively for the 030 and
  442.             the 020, but I choose not to do so for orthogonality).
  443.             Don't try it, the mmu.library will call the exec exception
  444.             handler directly in case you attempt this.
  445.  
  446.             Hence, you cannot feed the instruction pipeline of the
  447.             CPU manually.
  448.  
  449. exd_ReturnPC        The program counter of the instruction that caused the
  450.             fault. This might be only an approximate value due to the 
  451.             instruction prefetch feature of all CPUs of the 680x0
  452.             family. In case a branch was performed after the faulty
  453.             instruction was loaded, and before it was detected, this
  454.             PC might be completely useless. However, the program
  455.             is guaranteed to continue "at the right place".
  456.  
  457.             In case you set the EXDF_CALL flag, this field should be
  458.             set by your handler to the address of a small procedure 
  459.             which will be called in user mode, in the context of the 
  460.             task that caused the exception. This routine could, for 
  461.             example, send a message out to a "daemon" to get the 
  462.             fault repaired and could run into a WaitPort() to get 
  463.             an answer from the daemon.
  464.             The user routine has access to all registers of the faulty 
  465.             program, and must therefore preserve all registers unless 
  466.             it attempts to alter them "on purpose". The exception data
  467.             IS NO LONGER AVAILABLE, neither in the mmu library base
  468.             nor in any register. If you want to make use of it, make a
  469.             copy of it in the exception handler to a private place and
  470.             access it in this user routine.
  471.     
  472.             Alternatively, use the "message hook" mechanism of the
  473.             library which provides all this for you already if you don't
  474.             want to get a headache.
  475.  
  476.             The user routine should then return with a "RTS" to the
  477.             library code (note that the stacked PC points to some code
  478.             in the library, not to the faulty code itself! It's truely
  479.             deep magic to restore all this information) which will then    
  480.             rerun the faulty instruction.
  481.  
  482.             If you haven't been able to repair the cause of the fault,
  483.             the exception hook will be called again!
  484.  
  485. exd_Flags        A combined input/output flags long word. Amongst private
  486.             flags you'd better not care about, the following input
  487.             flags are available:
  488.  
  489.     EXDF_WRITE        a write fault if set. If reset, a read fault.
  490.     EXDF_INSTRUCTION    a fault on fetching an instruction. 
  491.                 As a special case, this *could* be a write fault
  492.                 if someone tried to write out instruction data
  493.                 with an instruction function code using the 
  494.                 "moves" instruction. This is actually unsupported
  495.                 by the library and should be avoided.
  496.     EXDF_WRITEPROTECTED    failed due to write protection of the destination.
  497.     EXDF_SUPERVISOR        failed due to supervisor only protection of the
  498.                 source/destination.
  499.     EXDF_WRITEDATAUNKNOWN    the write data was lost, exd_Data is invalid.
  500.                 Remember that you MUST set the MAPP_REPAIRABLE
  501.                 property flag for those pages you want write data
  502.                 for, and you should only set this bit if you really
  503.                 really want them. It means quite a lot of trouble
  504.                 for the library to provide the write data, hence
  505.                 things are not getting faster with it.
  506.     EXDF_MISALIGNED        The access was misaligned, i.e. more than one
  507.                 page was involved in the access. Prepare to
  508.                 swap in more than one page, for example.
  509.  
  510.             The following flags can be set by your code to let the 
  511.             library know what to do about the fault:
  512.  
  513.     EXDF_READBACK        abort a faulty read and provide the exd_Data word
  514.                 as input for the CPU. Do not try to rerun the access.
  515.     EXDF_WRITECOMPLETE    abort a faulty write, do not try to rerun it.
  516.     EXDF_CALL        call routine whose address is in exd_ReturnPC in
  517.                 user mode in the context of the task that caused
  518.                 the exception. This routine will be run as "sub-        
  519.                 routine" of the task that faulted, and might be
  520.                 used to sent out a message and wait for its reply
  521.                 to get the missing page fixed by another supervisor
  522.                 task. 
  523.                 THIS FUNCTION IS NOT AVAILABLE for a supervisor
  524.                 context. The mmu.library will guru in case you try
  525.                 to.
  526.                 Especially, the message hook mechanism described
  527.                 below uses this flag.
  528.                 Note that the library does not check for you whether
  529.                 Wait()-ing is useful here, as for example if the task
  530.                 is in Forbid state. It's the matter of the exception
  531.                 hook to check this.
  532.                 The library message hook exception does
  533.                 this, for example.
  534.  
  535. exd_Properties        The property flags of the page that was responsible for 
  536.             the fault.
  537.  
  538. exd_NextProperties    In case of a misaligned access, the flags of the second 
  539.             page involved in the access.
  540.  
  541. exd_internal        Leave this alone.
  542.  
  543. exd_FunctionCode    The function code of the access. The following values 
  544.             should be expected:
  545.  
  546.                 For the user context hooks:
  547.         1            User data access
  548.         2            User code access
  549.  
  550.                 For the a supervisor context and its hooks:
  551.         5            Supervisor data access
  552.         6            Supervisor code access
  553.  
  554.                 All remaining function codes relate to physical bus errors 
  555.                 and should not be passed thru to your context hook.
  556.  
  557. exd_Level        The level of the MMU tree at which the access fault happend 
  558.             and at which the MMU descriptor resides.
  559.             This NEED NOT to be the "page level" for early termination 
  560.             descriptors or invalid descriptors at a higher level. 
  561.             Experts should note that this is not even guaranteed for
  562.             the 040 or 060!
  563.             Furthermore, in case of an indirect descriptor, this is the 
  564.             level of the pointer pointing to the final page descriptor, 
  565.             not the level of the real page descriptor. 
  566.                 
  567.             This is advanced information you usually should not care 
  568.             about.    
  569.  
  570.             Level A of the MMU tree is encoded as "0", level B as "1" 
  571.             and so on. Note that this numbering is different from the
  572.             MC680x0 internal counting.
  573.  
  574.                 
  575. exd_NextLevel        In case of a misaligned access, the level of the second 
  576.             descriptor involved in the fault.
  577.  
  578. exd_DataRegs        A copy of the data registers at the time the fault happened.
  579.             These images are copied back as soon as the exception
  580.             terminates, hence a "higher magic" exception handler could
  581.             alter these...
  582.  
  583. exd_AddrRegs        A copy of the adress registers, but without the stack
  584.             pointer.
  585.  
  586. exd_SSP            The supervisor stack pointer. This points directly to the
  587.             processor specific exception stack frame. The first UWORD
  588.             of this stack frame is the copy of the status register at
  589.             the time of the fault.
  590.             BE WARNED! Everything else is processor specific, the
  591.             mmu.library might also want to modify this exception stack
  592.             frame, so hands off!
  593.  
  594. exd_USP            The user stack pointer.
  595.  
  596. exd_SysBase        A pointer to the library base of the "exec.library". DO NOT 
  597.             ACCESS ABSEXECBASE within the exception handler. Use either 
  598.             a private copy, or this pointer.
  599.             NOT FOLLOWING THIS RULE MIGHT BE FATAL!
  600.  
  601. exd_MMUBase        A pointer to the library base of the mmu.library, also in
  602.             register a6.
  603.  
  604. Additional notes about the exception handlers
  605. ---------------------------------------------
  606.  
  607. In case you're going to write an automatic stack extension program, you
  608. should keep in mind that the EXDF_CALL mechanism requires about 300 bytes 
  609. of user stack space. Similar, task switching takes some user stack, too. 
  610. The library message hook is prepared to handle this situation by swapping
  611. in its private stack space. 
  612.  
  613. For the same reason, you might have to add "Switch" and "Launch" handlers
  614. to allow exec to store the user registers safely. Unfortunately, this
  615. is done with supervisor accessed going to the user stack, and not with a
  616. "moves".
  617.  
  618.  
  619. Additional wierdos to watch out for
  620. -----------------------------------
  621. There are unfortunately a number of "features" of each CPU which should not
  622. go unmentioned:
  623.  
  624. The 68020/68851 and 68030:
  625.  
  626.     Execution of instructions in a access-protected "zero page" is really,
  627.     really slow. Please keep this in mind!
  628.     "moves" to instruction space is unsupported (goes for all other CPUs
  629.     as well).
  630.  
  631.     The FPU and exceptions: This is a dark chapter in exception handling.
  632.     Of a faulty fmove, only the first two long words are checked by the
  633.     68030 and therefore at most two hits get reported, all others go
  634.     unnoticed. Of a faulty fmovem, only the first two long words hits get
  635.     reported, too. The CPU will ignore all other hits and continue 
  636.     execution.
  637.     This means specifically that a Debugger tool might not be able to see
  638.     all hits that happened on these instructions, and you will not be
  639.     able to capture them for private use.
  640.     VM systems shouldn't have much problems with that, though, since the
  641.     invalid page should have been swapped in and each access can hit at
  642.     most two pages at once if it is misaligned. However, you must be    
  643.     prepared that the mmu.library will not be able to set the "misaligned"
  644.     flag correctly in this case. Rather, the CPU will be re-run with only
  645.     partially repaired pages, and might invoke an exception handler
  646.     again.
  647.  
  648.  
  649. The 68040:
  650.  
  651.     Movem writeback data is not always available, and certain movems can't
  652.     be continued safely. In case a movem read or write goes to an invalid
  653.     page other than at level 2 or 3, the mmu library has to abort the movem
  654.     completely. There's nothing I can do against it. To avoid this situation
  655.     in case you really need the movem data, set the MAPP_REPAIRABLE property.
  656.  
  657.     Movems to a register included in the register list itself might not be
  658.     rerun safely in all circumstances. Avoid them.
  659.  
  660.     Readback data is only available for all destination registers at once.
  661.  
  662.     The FPU and exceptions: Even more problems than with the 030. 
  663.     If a fmove or fmovem moves more than two long words, for example a
  664.     fmove.x or any fmovem, the processor will only notice the first 
  665.     access of a faulty page. If the instruction would catch more than
  666.     one hit, the processor restarts the instruction completely from the
  667.     beginning. This means for debugging tools that you will *not* be
  668.     able to fix a faulty instruction of this kind at all, the processor
  669.     will loop forever. Note that even disassembling the instruction at
  670.     the PC will not help because the PC might point to an FPU instruction
  671.     even if the hit was caused by the instruction before. Hence, the
  672.     following two instructions
  673.  
  674.         move.l d0,(a3)
  675.         fmovem.x fp0,(a3)
  676.  
  677.     with a3 pointing to an invalid page, will both invoke the exception
  678.     handler with the same PC value, namely the address of the fmove!
  679.  
  680.     This might be a problem for VMM systems as well: Because there's no
  681.     single flag that tells whether the hit was caused by an FPU instruction
  682.     or not, the processor might re-run a FPU instruction as mentioned
  683.     above again, possibly accessing the two different pages. If the VMM
  684.     system would have swapped in the second page by the first hit, and
  685.     removed the first page accessed by this instruction from memory,
  686.     re-running this instruction will cause another VMM hit, this time
  687.     from the first page. It is therefore important that a VMM system
  688.     *MUST NOT* swap out a page previously swapped in. At least two pages
  689.     must be available at once.
  690.  
  691.  
  692. The 68060:
  693.  
  694.     The library handles branch cache flushes transparently, no need to
  695.     worry about them. So much for the good point.
  696.  
  697.     Writeback data is usually not available unless the library emulates
  698.     this with some heavy magic and is told to do so with the MAPP_REPAIRABLE
  699.     flag. Things are getting even worse if no exception handler wants to
  700.     make use of the writeback data and returns with the EXDF_WRITEBACK flag
  701.     cleared. In this case, the mmu.library tries to rerun the faulty 
  702.     instruction again, even though it already executed. It tries to rebuild
  703.     all the registers (except for the FPU registers and the supervisor model
  704.     and the SSP) and then returns to the PC of the faulty instruction.
  705.     Whether this mechanism is reliable or not has to be proven.
  706.  
  707.     Except that, all 040 restrictions regarding movems apply here again, see
  708.     above.
  709.  
  710.     In case of a non-locked read-modify-write access, as for example a
  711.     addq.l #1,(ax), the library will call the context hooks twice, once
  712.     with the read data, and then again with the write data. However, things
  713.     are getting rather nasty in case of a misaligned RMW access of which
  714.     one part of the access is valid and the other part is not. The 060
  715.     manual states that these accesses can't be rerun safely because parts
  716.     of the data might have been written back already, and rerunning the
  717.     instruction might cause this wrong data to be re-used again. I can't
  718.     comment on that feature because I haven't tried to reproduce it yet,
  719.     but it may reduce reliability of the 060 for virtual memory appli-
  720.     cations.
  721.  
  722. ------------------------------------------------------------------------------
  723.  
  724. About the page access exception:
  725.  
  726.  
  727. This is not a true exception, but is installed and handled the like. It is
  728. setup with AddContextHook(MADTAG_TYPE,MMUEH_PAGEACCESS,....) as all other
  729. exception handlers. The page access hook "hooks in" between the high level
  730. functions SetProperties/GetProperties/RebuildTree and the low level functions
  731. SetPageProperties/GetPageProperties at the other side. It provides a method
  732. to modify the MMU tree on the low level transparently to the high level 
  733. functions. 
  734.  
  735. The page access handlers are called whenever RebuildTree() tries to re-
  736. install a page descriptor with the MAPP_SINGLE property bit set. If so, your
  737. handler is allowed to modify this page descriptor. However, you should 
  738. remember that the high-level functions are not aware of this modification,
  739. so this feature should be used carefully.
  740.  
  741. A possible application would be a "Guardian Angel" type program: The idea
  742. is here to mark "free" memory as MAPP_INVALID to be able to detect illegal
  743. memory accesses. Since an AllocMem() has to mark the memory valid it
  744. allocated, the MMU tables have to be adjusted for each allocation. Similary,
  745. released memory has to be made unavailable on a FreeMem(). On the 
  746. other hand, AllocMem() is not allowed to break a Forbid() and is hence not
  747. able to call the high-level functions - which might do so. It *has* to use
  748. the low level SetPageProperties(). Since the low level functions do not
  749. inform the higher level about the modification, a program adjusting the
  750. MMU descriptor with the high-level functions will un-do the modifications
  751. made by AllocMem() before. The solution here is to install a page access 
  752. handler that checks whether the higher level is going to re-install one
  753. of the modified page descriptors, to intercept here and to set the 
  754. MAPP_INVALID flag correctly, by testing whether the addressed memory page is
  755. "free" or not.
  756.  
  757.  
  758.  
  759. Your handler is called with the page access data structure - see below - in
  760. a0, with the provided user data from MADTAD_DATA in a1 and a4 and the 
  761. library pointer in a6. Registers d0-d1/a0-a1/a4-a5 are scratch registers,
  762. a6 IS NOT. In case your handler returns with the Z flag set, the library
  763. aborts calling other handlers of lower priority.
  764.  
  765. Remember that you're called in supervisor mode with all interrupts dis-
  766. abled, as for all other exception handlers. Your code should better be
  767. fast!
  768.  
  769.  
  770. Now for the structure:
  771.  
  772. struct PageAccessData {
  773.         ULONG                    pgad_Level;
  774.         void                    *pgad_Address;
  775.         ULONG                   *pgad_Destination;
  776.         struct MMUContext       *pgad_Context;
  777.         struct MMUBase          *pgad_MMUBase;
  778.         ULONG                    pgad_Properties;
  779.         ULONG                    pgad_UserData;
  780. };
  781.  
  782.  
  783. pgad_Level:            The level at which the MMU descriptor has to be build
  784.                 for. This is zero for level A, one for level B and so
  785.                 on. Note that this numbering is different from the
  786.                 internal MC68K scheme.
  787.                 Since this handler is only called for MAPP_SINGLE
  788.                 descriptors, this will always be the page level of the
  789.                 MMU tree. However, what the page level *is* is up to
  790.                 the depth of the MMU tree and may vary.
  791.  
  792. pgad_Address:            The logical address the descriptor to be build will 
  793.                 handle. Hence, this gives the address that is to be
  794.                 translated or mapped.
  795.  
  796. pgad_Destination:        The address the true hardware descriptor will be written
  797.                 to. There's little reason to make use of this entry.
  798.  
  799. pgad_Context:            The context the MMU tree being rebuild belongs to. This
  800.                 is the context you installed the page access handler in.
  801.  
  802. pgad_MMUBase:            The library base address.
  803.  
  804. pgad_Properties:        The page properties, defined in mmu/context.h. This 
  805.                 defines which kind of hardware descriptor the library
  806.                 will build for you.
  807.  
  808. pgad_UserData:            This field will be used for MAPP_SWAPPED, MAPP_INVALID,
  809.                 MAPP_REMAPPED, MAPP_BUNDLED and MAPP_INDIRECT 
  810.                 descriptors. It will contain user specific information
  811.                 like a hard disk position for MAPP_SWAPPED or 
  812.                 MAPP_INVALID pages, the destination address for 
  813.                 MAPP_REMAPPED and MAPP_BUNDLED pages, and the destination
  814.                 descriptor for MAPP_INDIRECT. It is not available if the
  815.                 MAPP_REPAIRABLE bit is set. In case you modify the
  816.                 properties, you possibly need to correct this field, too.
  817.  
  818.